#include "TCPPoint.h"


#define TEST
#include <iostream>
using std::cout;
#define ENDTEST

TCPPoint::TCPPoint(void)
:_connection(-1)
{
	_sock = 0;
	_backlog = 10;
	_socketCreated = false;
	_errorMessgae = "socket not created";

	if (CreateSocket())
	{
		_socketCreated = true;
	}
}

TCPPoint::~TCPPoint(void)
{
	Close();
}


bool TCPPoint::CreateSocket()
{
	_sock = 0;
	WSADATA WSAData;
	if(WSAStartup(MAKEWORD(1, 1), &WSAData))
	{
		WSACleanup();
		_errorMessgae = "can not initialize WSAData";
		return false;
	}

	if ((_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
	{
		WSACleanup();
		_errorMessgae = "can not create socket";
		return false;
	}
	return true;
}

bool TCPPoint::bindSocket(string ip, int port)
{
	if (!_socketCreated)
	{
		_errorMessgae = "socket not created";
		return false;
	}

	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(port);
	if (ip == "")
	{
		serverAddr.sin_addr.s_addr = INADDR_ANY;
	}
	else
	{
		serverAddr.sin_addr.s_addr = inet_addr(ip.c_str());
	}

	memset(&(serverAddr.sin_zero), 0, sizeof(serverAddr.sin_zero));

	if (bind(_sock, (sockaddr*)&serverAddr, sizeof(sockaddr)) == -1)
	{
		WSACleanup();
		_errorMessgae = "can not bind the socket to port";
		return false;
	}
	return true;
}

bool TCPPoint::Listen(string ip, int port)
{
	if (!_socketCreated)
	{
		_errorMessgae = "socket not created";
		return false;
	}

	if (!bindSocket(ip, port))
	{
		return false;
	}

	if (listen(_sock, _backlog) == -1)
	{
		WSACleanup();
		_errorMessgae = "can not listen";
		return false;
	}
	return true;
}

bool TCPPoint::Connect(string ip, int port)
{
	if (!_socketCreated)
	{
		_errorMessgae = "socket not created";
		return false;
	}

	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr(ip.c_str());
	serverAddr.sin_port = htons(port);
	memset(&(serverAddr.sin_zero), 0, sizeof(serverAddr.sin_zero));

	if (connect(_sock, (sockaddr*)&serverAddr,
		sizeof(sockaddr)) == -1)
	{
		_connection = Connection(-1);
		_errorMessgae = "fail to connect to " + ip;
		return false;
	}
	_connection = setConnection(_sock, serverAddr);
	return true;
}

Connection TCPPoint::GetConnection()
{
	return _connection;
}

Connection TCPPoint::Accept()
{
	sockaddr_in clientAddr;
	int size = sizeof(sockaddr_in);
	int sock = accept(_sock, (sockaddr*)&clientAddr, &size);

	if (sock == -1)
	{
		WSACleanup();
		_errorMessgae = "fail to accept";
		return Connection(-1);
	}
	return setConnection(sock, clientAddr);
}

string TCPPoint::GetErrorMessage()
{
	return _errorMessgae;
}


void TCPPoint::Close()
{
	if (_socketCreated)
	{
		_connection.Dispose();
		closesocket(_sock);
		WSACleanup();
		_socketCreated = false;
	}
}

Connection TCPPoint::setConnection(int sock, sockaddr_in remoteAddr)
{
	sockaddr_in localAddr;
	int size = sizeof(sockaddr_in);
	getsockname(sock, (sockaddr*)&localAddr, &size);

	return Connection(sock,
		inet_ntoa(localAddr.sin_addr),
		ntohs(localAddr.sin_port),
		inet_ntoa(remoteAddr.sin_addr),
		ntohs(remoteAddr.sin_port));
}
